/*
 * BuiltInCommand.cpp
 *
 *  Created on: May 26, 2011
 *      Author: Stijn, Bart, Dave
 */


#include "Command.h"
#include "Shell.h"

#include "BuiltInCommand.h"

BuiltInCommand::BuiltInCommand() {

}

BuiltInCommand::~BuiltInCommand() {

}

void BuiltInCommand::executeBuildIn(const char* command, int argc, char* const * argv) {
	if (strcmp(command, "cd") == 0) {
		execCd(argc, argv);
	} else if (strcmp(command, "jobs") == 0) {
		jobs();
	} else if (strcmp(command, "nice") == 0) {
		if(argc >= 3) {
			nice(argc, argv);
		}
	} else if (strcmp(command, "wait") == 0) {
		//		cout << argv[0] << " of " << argv[1] <<endl;
		//		cout << "your mom" << endl;
		if(argc == 2) {
			wait(atoi(argv[1]));
		}
	}
}

int BuiltInCommand::execCd(int argc, char* const * argv) {
	int option;
	char* directory;

	char* const help = (char*) "Usage: ";

	while ((option = getopt(argc, argv, "h")) != -1) {
		switch (option) {
		case 'h':
			fprintf(stdout, "%s\n", help);
			break;

		case '?':
		default:
			abort();
			break;
		}
	}

	if (strcmp(argv[argc - 1], "cd") == 0) {
		// If no parameters, change to home directory
		directory = getenv("HOME");
	} else {
		directory = argv[argc - 1];
		DIR* dir = opendir(directory);
		if (dir == NULL) {
			fprintf(stderr, "The specified path does not exists.\n");
			return -1;
		} else
			closedir(dir);
	}

	return chdir(directory);
}

int BuiltInCommand::nice(int argc, char* const * argv) {
	int result = 0;
	int inc = atoi(argv[1]);
	if(inc < 0) {
		std::cout << "Syntax error" << std::endl;
	} else {
		if(inc == 0) std::cout << "Please enter a correct increment" << std::endl;
		else {
			Command* command = new Command(argv[2], Shell::readPathVariables());
			command->setPriorityInc(inc);
			if(argc >= 4) {
				for(int i = 3; i < argc; ++i) {
					command->addArgument(argv[i]);
				}
			}
			command->runCommand();
			delete command;
		}
	}
	return result;
}

int BuiltInCommand::jobs() {
	int pos = 1;
	for (std::vector<int>::iterator iter = backgroundPids->begin();
			iter != backgroundPids->end(); ++iter) {
		std::string info = getProccesInfo(*iter, pos);
		if (strcmp(info.c_str(), "terminated") == 0) {

		} else {
			std::cout << info << std::flush;
		}
		pos++;
	}
	return 1;
}

void BuiltInCommand::setPids(std::vector<int>* pids) {
	backgroundPids = pids;
}

void BuiltInCommand::wait(pid_t cpid) {
	int status = -1;
	//	cout << "waiting for " << cpid << endl;
	if (cpid > 0) {
		do {
			pid_t errorCheck = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
			if (errorCheck == -1) {
				perror("waitpid");
				break;
				//exit(EXIT_FAILURE);
			}
			if (WIFEXITED(status)) {
				if (status != 0)
					printf("exited, status=%d\n", WEXITSTATUS(status));
			} else if (WIFSIGNALED(status)) {
				printf("killed by signal %d\n", WTERMSIG(status));
			} else if (WIFSTOPPED(status)) {
				printf("stopped by signal %d\n", WSTOPSIG(status));
			} else if (WIFCONTINUED(status)) {
				printf("continued\n");
			}
		} while (!WIFEXITED(status) && !WIFSIGNALED(status));
		if (status != 0) {
			std::cout << "Process: " << cpid << std::endl;
		}
	} else {
		std::cout << "not a (positive) number" << std::endl;
	}
}

std::string BuiltInCommand::getProccesInfo(int pid, int pos) {
	std::string returnstatement = "";
	std::string dir = ("/proc/" + intToString(pid) + "/stat");

	FILE *fpstat = fopen(dir.c_str(), "r");
	if (fpstat != NULL) {
		char name[80];
		char state;
		fscanf(fpstat, "%*d %s %c", name, &state);
		if (name != NULL) {
			returnstatement = ("[" + intToString(pos) + "]\t" + intToString(pid)
					+ "\t" + state + '\t' + name + "\n");
		} else {
			return "terminated";
		}
		fclose(fpstat);
	}
	return returnstatement;
}

std::string BuiltInCommand::intToString(int i) {
	char temp[30];
	sprintf(temp, "%d", i);
	return temp;
}
